package org.bukkit.pm.afk;

import java.io.File;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

/**
 * Afk for Bukkit
 *
 * @author patamau
 */
public class AfkPlugin extends JavaPlugin {
	private final static Logger LOGGER = Logger.getLogger("Minecraft");
	
    private final AfkPlayerListener _playerListener = new AfkPlayerListener(this);
    private final HashMap<String, AfkPlayer> _players = new HashMap<String, AfkPlayer>();

    public static String VERSION;
    //XXX: load deadzone from properties file!?
    public static long AFK_DEADZONE = 2000; //in milliseconds
    
    public AfkPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader) {
        super(pluginLoader, instance, desc, folder, plugin, cLoader);
    }
    
    public void log(Level level, String message){
    	LOGGER.log(level,"[Afk] "+message);
    }

    public void onEnable() {
        // Register our events
        PluginManager pm = getServer().getPluginManager();
        pm.registerEvent(Event.Type.PLAYER_COMMAND, _playerListener, Priority.Normal, this);
        pm.registerEvent(Event.Type.PLAYER_JOIN, _playerListener, Priority.Normal, this);
        pm.registerEvent(Event.Type.PLAYER_MOVE, _playerListener, Priority.Normal, this);
        pm.registerEvent(Event.Type.PLAYER_QUIT, _playerListener, Priority.Normal, this);
        
        PluginDescriptionFile pdfFile = this.getDescription();
        VERSION = pdfFile.getVersion();
        log(Level.INFO, VERSION+" enabled");
    }
    
    public AfkPlayer[] getAfkPlayers(){
    	AfkPlayer[] aps = _players.values().toArray(new AfkPlayer[_players.size()]);
    	return aps;
    }
    
    /**
     * Tells if a player is in the afk list
     * @param p
     * @return
     */
    public boolean isAfk(Player p){
    	return _players.keySet().contains(p.getName());
    }
    
    /**
     * Add player to list and modify the display name
     * @param p
     */
    public void toggleAfk(Player p, String reason){
    	boolean afk = isAfk(p)?false:true;    	
    	if(afk){    		
    		p.setDisplayName("[AFK] "+p.getDisplayName());
        	_players.put(p.getName(), new AfkPlayer(p, System.currentTimeMillis(), reason));
        	String msg = p.getName()+" has gone afk";
        	if(reason!=null){
        		msg += ": "+reason;
        	}
        	broadcast(msg);
    	}else{
    		//check time (prevent user to leave afk status too early)
    		AfkPlayer ap = _players.get(p.getName());
    		if(ap==null){ //assert ap
    			log(Level.WARNING, "trying to set AFK status OFF for a non recorded player '"+p.getName()+"'");
    			return;
    		}
    		long dt = System.currentTimeMillis()-ap.getTime();
    		if(dt<AFK_DEADZONE){
    			//prevent toggling too rapidly
    			return;
    		}
    		int i = p.getDisplayName().indexOf("[AFK]");
    		//only remove the <Afk> string
    		if(i>=0){
    			String head = p.getDisplayName().substring(0, i);
    			p.setDisplayName(head+p.getDisplayName().substring(i+4));
    		}
    		removePlayer(p);
    		broadcast(p.getName()+" is back!");
    	}
    }
    
    /**
     * Force player to be removed from the afk list
     * @param p
     */
    public void removePlayer(Player p){
    	_players.remove(p.getName());
    }
    
    /**
     * Used to broadcast messages to all the connected players
     * @param message
     */
    public void broadcast(String message){
    	message = "[Afk] "+message;
    	for(Player p: this.getServer().getOnlinePlayers()){
    		p.sendMessage(message);
    	}
    }
    
    /**
     * Store properties
     */
    public void onDisable() {
       log(Level.INFO,"disabled");
    }
}
